""" Property of TwoCubed s.r.l 2009
    Released under the Apache 2.0 License
    
    @author: Michele SAMA aka -RAX-
"""

import re
import unittest

from utils import call_view, create_request, create_user, is_resolver,\
        DEFAULT_PARAMETERS
from django.http import Http404,  HttpRequest


class UrlAutoTestCase(unittest.TestCase):
    """ Creates a new test for each url and invokes all the related views
        with the parameters specified in the url itself.
        
        Overriding classes must redefine the following fields:
        * assignment_patterns
        * exclusion_list
        * url_under_test
        * request_user
    """
    
    assignment_patterns = DEFAULT_PARAMETERS
    
    """ Specifies a list o prefixes which should be excluded
        by the executions. This is mean to avoid testing third party
        components.
    """
    exclusion_list = [
            "^admin",
            "^accounts",
            "^i18n",
            ]
    
    get_parameters = dict() 
    
    post_parameters = dict()
    
    """ The set of url under test.
    """
    url_under_test = []
    
    """ The instance of user which should be authenticated in the request
        or None if the request should be not authenticated.
    """
    request_user = None

   
    def _compile_assignments(self, assignments):
        compiled_patterns = []
        for pattern in assignments:
            prog = re.compile(pattern[0])
            compiled_patterns.append((prog, pattern[1]))
        return compiled_patterns
    
    def setUp(self, verbose_logging = False,
              invoke_get = True, invoke_post = True):
        """ Sets up the test execution.
            @param verbose_logging: pif True print a verbose logging
                    of the invoked requests. 
            @param invoke_get: perfom get requests.
            @param invoke_post: perform post requests.
        """ 
        
        self.log = verbose_logging
        self.get = True if invoke_get else False
        self.post = True if invoke_post else False
        self.request_user = create_user()
        self.compiled_assignments =\
                self._compile_assignments(self.assignment_patterns)
    
    def tearDown(self):
        pass

    def runTest(self):
        """ Convenience method to test all the urls specified in
            self.url_under_test
        """
        if self.get:
            self.__process_list(self.url_under_test, self.request_user, 'GET')
    
        if self.post:
            self.__process_list(self.url_under_test, self.request_user, 'POST')


    def __process_list(self, urls, user, method):
        """ Recursively explores the given urls.
            
            @param urls: a list of instances of RegexURLResolver or
                    RegexURLPattern
        """
        for pattern in urls:
            url = pattern.regex
            if [True for excluded in self.exclusion_list\
                        if url.pattern.startswith(excluded)]:
                    if self.log:
                        print "Skipping: %s." % url.pattern
                    continue
            
            if is_resolver(pattern):
                if self.log:
                    print "%s" % pattern.urlconf_module
                self.__process_list(pattern.url_patterns, self.request_user, method)
            else:
                view = pattern.callback
                if self.log:
                    print "Processing: %s(%s): %s" %\
                            (url.pattern, url.groupindex, view.__name__) 
                
                request = create_request(self.request_user, method)
                kwargs = call_view(pattern, request, self.compiled_assignments)                    
                
                if self.log:
                    print "Running %s(%s)." % (view.__name__, kwargs)
                else:
                    print "Running %s." % (view.__name__) 
                try:
                    view(*(), **kwargs)
                except Http404, err:
                    print "%s - A 404 occurred: %s" % (view.__name__, err)
                    print "Please check the setUp of this test."
                except NotImplementedError, err:
                    print "%s - NOT IMPLEMENTED: %s" % (view.__name__, err)
                
                if self.log:
                    print "\n"

    
        

